module ALU (
    input   logic           clk,
    input   logic           rst_n,

    input   logic   [2:0]   ALU_OP,
    input   logic   [31:0]  A,
    input   logic   [31:0]  B,
    output  logic   [31:0]  F,
    output  logic           ZF,
    output  logic           OF,
    output  logic           SF,
    output  logic           PF,
    output  logic           CF
);


reg [32:0] result;

// verilator lint_off WIDTH
always_comb begin
    case (ALU_OP)
        3'd0: result = A & B;
        3'd1: result = A | B;
        3'd2: result = A ^ B;
        3'd3: result = ~(A | B);
        3'd4: result = A + B;
        3'd5: result = A - B;
        3'd6: result = (A < B) ?'b1 :'b0;
        3'd7: result = B << A;
        default: result = 'd0;
    endcase
end
// verilator lint_on WIDTH

always_comb begin
    F   = result[31:0];
end

always_ff @( negedge clk, negedge rst_n ) begin
    if(!rst_n) begin
        ZF <= 1'b0;
        OF <= 1'b0;
        SF <= 1'b0;
        PF <= 1'b0;
        CF <= 1'b0;
    end
    else begin
        ZF <= ~(| (result[31:0]) );
        OF <= A[31] ^ B[31] ^ result[31] ^ result[32];
        SF <= result[31];
        PF <= ~(^ (result[31:0]));  // even 1, odd 0
        CF <= (ALU_OP == 3'd4) ?result[32] :    // add
            (ALU_OP == 3'd5) ?(~result[32]) : // sub
            1'b0;
    end
end


endmodule
